using System;
using System.Linq;
using System.Threading.Tasks;
using Coravel.Invocable;
using Microsoft.Extensions.Logging;
using System.Net.Http;
using System.Collections.Generic;
using Newtonsoft.Json;
using CRM.Models;

namespace CRM.Jobs
{
    public class TimingGetBuyerData : IInvocable
    {
        private readonly MyDbContext _dbContext;
        private readonly ILogger<TimingGetBuyerData> _logger;
        private readonly IHttpClientFactory _httpClientFactory;

        public TimingGetBuyerData(MyDbContext dbContext, ILogger<TimingGetBuyerData> logger, IHttpClientFactory httpClientFactory)
        {
            _dbContext = dbContext;
            _logger = logger;
            _httpClientFactory = httpClientFactory;
        }
        // 买家数据定时任务
        public async Task Invoke()
        {
            // 拉取日志
            BuyerDataPullLog logPull = new();
            // [LogPull]-CreateTime
            logPull.CreateTime = DateTime.Now;
            // 验证码识别日志
            VerifyCodeLog verify = new();
            // 访问api获取验证码Json[(成功/失败),(info:),(json)]
            (var getCodeImgState, var msg1, var jCode) = await GetCodeImg();
            if (getCodeImgState)
            {
                //verify.CodeImg = $"data:image/gif;base64,{jCode.Img}";
                // 调用图片识别api--识别图片[(成功/失败),(info:),(图片base64),(识别结果)]
                (var distinguishCodeImgState, var msg2, var imgUrl, var code) = await DistinguishCodeImg(jCode.Img);
                verify.DistinguishTime = DateTime.Now;
                verify.CodeImg = imgUrl;
                if (distinguishCodeImgState)
                {
                    verify.Code = code;
                    // 模拟登录
                    (var simulateLoginState, var msg3, var token) = await SimulateLogin(jCode, code);
                    if (simulateLoginState)
                    {
                        // 国外
                        var url_foreign = "http://www.styizhan.com/prod-api/buyer/search/list?pageNum=1&pageSize=100&type=1&keyword=&categoryStub=";
                        var count1 = await CrawlData(url_foreign, token);
                        // 国内
                        var url_internal = "http://www.styizhan.com/prod-api/buyer/search/list?pageNum=1&pageSize=100&type=2&keyword=&categoryStub=";
                        var count2 = await CrawlData(url_internal, token);
                        logPull.LogInfo = "成功";
                        logPull.PullCount = count1 + count2;
                    }
                    else
                    {
                        logPull.LogInfo = msg3;
                    }
                }
                else
                {
                    logPull.LogInfo = msg2;
                }
            }
            else
            {
                logPull.LogInfo = msg1;
            }
            // [LogPull]-CreateTime
            logPull.EndTime = DateTime.Now;
            await _dbContext.AddAsync(logPull);
            await _dbContext.SaveChangesAsync();
            verify.BuyerDataPullLog = logPull;
            await _dbContext.AddAsync(verify);
            await _dbContext.SaveChangesAsync();
        }

        // 访问api获取验证码Json [1]
        public async Task<(bool, string, JCode)> GetCodeImg(int reTryCount = 0)
        {
            var verificationCodeUrl = "http://www.styizhan.com/prod-api/captchaImage";
            var request = new HttpRequestMessage(HttpMethod.Get, verificationCodeUrl);
            using var client = _httpClientFactory.CreateClient();
            var response = await client.SendAsync(request);
            // 请求失败就继续发送请求
            if (response.IsSuccessStatusCode)
            {
                var json = await response.Content.ReadAsStringAsync();
                var jCode = JsonConvert.DeserializeObject<JCode>(json);
                if (string.IsNullOrEmpty(jCode.Img))
                {
                    return (false, $"{nameof(GetCodeImg)}-请求验证码为空", null);
                }
                if (string.IsNullOrEmpty(jCode.Uuid))
                {
                    return (false, $"{nameof(GetCodeImg)}-请求验证码uuid为空", null);
                }
                return (true, string.Empty, jCode);
            }
            else
            {
                while (reTryCount < 3)
                {
                    await Task.Delay(1000 * Convert.ToInt32(Math.Pow(2, reTryCount + 1)));
                    return await GetCodeImg(++reTryCount);
                }
                return (false, $"{nameof(GetCodeImg)}-请求失败", null);
            }
        }

        // 调用图片识别api 识别 图片 [2]
        public async Task<(bool, string, string, string)> DistinguishCodeImg(string ImageBase64, int reTryCount = 0)
        {
            (bool, string, string, string) falseData(int codeNum, string reason, string data = null)
            {
                _logger.LogError($"#{codeNum}:{reason} - {nameof(DistinguishCodeImg)}");
                if (data is not null)
                {
                    _logger.LogError($"#{codeNum}-data:{data} - {nameof(DistinguishCodeImg)}");
                }
                return (false, reason, $"data:image/gif;base64,{ImageBase64}", string.Empty);
            }
            var url = "http://api.ttshitu.com/predict";
            var username = "hellmen";
            var password = "198372djf";
            var request = new HttpRequestMessage(HttpMethod.Post, url);
            // var boundary = $"----WebKitFormBoundary{DateTime.Now.Ticks.ToString("x")}";
            // var body = new MultipartFormDataContent(boundary);
            var d = new Dictionary<string, string>();
            d.Add("username", username);
            d.Add("password", password);
            var typeid = "1003";//选使用的OCR模型 1003为数英混合2(优化版)
            d.Add("typeid", typeid);
            d.Add("image", ImageBase64);
            var c = new FormUrlEncodedContent(d);

            request.Content = c;
            using var client = _httpClientFactory.CreateClient();
            var response = await client.SendAsync(request);
            if (response.IsSuccessStatusCode)
            {
                var json = await response.Content.ReadAsStringAsync();
                var TtshituResponse = JsonConvert.DeserializeObject<TtshituResponse>(json);
                if (TtshituResponse is null)
                {
                    return falseData(100, "Json is null", json);
                }
                else
                {
                    if (TtshituResponse.success)
                    {
                        return (true, string.Empty, $"data:image/gif;base64,{ImageBase64}", TtshituResponse.data.result);
                    }
                    else
                    {
                        return falseData(115, "api result was false", json);
                    }
                }
            }
            else
            {
                const int AllowReTryTime = 3;
                if (reTryCount == AllowReTryTime - 1)
                {
                    return falseData(124, $"request fail,already retry {AllowReTryTime} times");
                }
                //-[1] 1 [2] 2 [3] 4
                //+[1] 2 [2] 4 [3] 8 
                await Task.Delay(1000 * Convert.ToInt32(Math.Pow(2, reTryCount + 1)));
                return await DistinguishCodeImg(ImageBase64, ++reTryCount);
            }
        }
        // 模拟登录 [3]
        public async Task<(bool, string, string)> SimulateLogin(JCode jCode, string code, int reTryCount = 0)
        {
            var url = "http://www.styizhan.com/prod-api/member/login";
            var username = "小白123";
            var password = "a53542316l";
            var uuid = jCode.Uuid;
            // // 验证码
            var request = new HttpRequestMessage(HttpMethod.Post, url);
            using var client = _httpClientFactory.CreateClient();
            var json = JsonConvert.SerializeObject(new { username = username, password = password, code = code, uuid = uuid });
            request.Content = new StringContent(json, null, "application/json");
            var Response = await client.SendAsync(request);
            if (Response.IsSuccessStatusCode)
            {
                var ResponseJson = await Response.Content.ReadAsStringAsync();
                var loginJson = JsonConvert.DeserializeObject<loginJson>(ResponseJson);
                _logger.LogError($"{ResponseJson}");
                if(string.IsNullOrEmpty(loginJson.token)){
                    return (false, $"{nameof(SimulateLogin)}--{ResponseJson}", null);
                }
                return (true, string.Empty, loginJson.token);
            }
            else
            {
                while (reTryCount < 3)
                {
                    await Task.Delay(1000 * Convert.ToInt32(Math.Pow(2, reTryCount + 1)));
                    return await SimulateLogin(jCode, code, ++reTryCount);
                }
                return (false, "模拟登录请求失败", string.Empty);
            }
        }
        // 获取拉取数据的id与数据库dataid做去重 
        public async Task<List<int>> GetDataids(string url)
        {
            List<int> dataIds = new();
            var request = new HttpRequestMessage(HttpMethod.Get, url);
            using var client = _httpClientFactory.CreateClient();

            var response = await client.SendAsync(request);
            if (response.IsSuccessStatusCode)
            {
                var resp = await response.Content.ReadAsStringAsync();
                var items = JsonConvert.DeserializeObject<Body_Json>(resp);
                var rows = items.Rows;
                var ls = rows.Select(a => a.Id).ToList();
                var dataIds_db = _dbContext.BuyersData.Select(a => a.DataId).ToList();
                foreach (var id in ls)
                {
                    if (!dataIds_db.Contains(id))
                    {
                        dataIds.Add(id);
                    }
                }
                return dataIds;
            }
            else
            {
                return dataIds;
            }
        }
        // 抓取 
        public async Task<int> CrawlData(string url, string token)
        {
            // (去重后的)新增条数
            var dataIds = await GetDataids(url);

            var url_search = "";
            List<BuyerData> bds = new();
            foreach (var id in dataIds)
            {
                url_search = $"http://www.styizhan.com/prod-api/buyer/search/{id}";
                var request = new HttpRequestMessage(HttpMethod.Get, url_search);
                request.Headers.Add("Authorization", "Bearer " + token);
                request.Headers.Add("Cookie", "Member-Token=" + token + "; Member-Name=YH3116104665; Member-Photo=/static/img/profile.473f5971.jpg; Member-Type=1");
                using var client = _httpClientFactory.CreateClient();
                var response = await client.SendAsync(request);
                if (response.IsSuccessStatusCode)
                {
                    var resp = await response.Content.ReadAsStringAsync();
                    var item = JsonConvert.DeserializeObject<Search_Json>(resp).Data;
                    BuyerData bd = new();
                    bd.DataId = item.Id;
                    bd.BuyerCompanyId = item.CompanyId;
                    bd.Type = (BuyerData.Types)Convert.ToInt32(item.Type);
                    bd.Title = item.Title;
                    bd.ProductCode = item.ProductCode;
                    bd.Image = item.Image;
                    bd.Details = item.Details;
                    bd.ReleaseTime = item.ReleaseTime;
                    bd.ExpireTime = item.ExpireTime;
                    bd.Country = item.Country;
                    bd.CountryFlag = item.CountryFlag;
                    bd.UrlLink = item.UrlLink;
                    bd.Address = item.Address;
                    bd.RequireQuantity = item.RequireQuantity;
                    bd.Contacts = item.Contacts;
                    bd.Mailbox = item.Mailbox;
                    bd.Wechat = item.Wechat;
                    bd.Phone = item.Phone;
                    bd.Mailbox = item.Mailbox;
                    bd.CategoryStubs = (item.CategoryStubs == null) ? null : item.CategoryStubs.ToString();
                    bd.Destination = item.Destination;
                    bd.RequireAmount = item.RequireAmount;
                    bd.TargetPrice = item.TargetPrice;
                    bd.SupplierArea = item.SupplierArea;
                    bd.Follow = item.Follow;
                    bd.State = BuyerData.States.Published;
                    bds.Add(bd);
                }
            }
            await _dbContext.BuyersData.AddRangeAsync(bds);
            // _logger.LogInformation("新增的买家数据:{count}", bds.Count);
            var count = await _dbContext.SaveChangesAsync();
            // 新增的行数
            return count;
        }
    }
    public class loginJson
    {
        public int code { get; set; }
        public string msg { get; set; }
        public string token { get; set; }

    }
    public class TtshituResponse
    {
        public bool success { get; set; }
        public string code { get; set; }
        public string message { get; set; }
        public dataObj data { get; set; }
        public class dataObj
        {
            public string result { get; set; }
            public string id { get; set; }

        }
    }
    public class JCode
    {
        public string Msg { get; set; }
        public string Img { get; set; }
        public int Code { get; set; }
        public string Uuid { get; set; }
    }
    public class Body_Json
    {
        public int Total { get; set; }
        public List<Row> Rows { get; set; }
        public int Code { get; set; }
        public string Msg { get; set; }
    }
    public class Search_Json
    {
        public int Code { get; set; }
        public Row Data { get; set; }
        public string Msg { get; set; }
    }
    public class Row
    {
        public int Id { get; set; }

        public string Type { get; set; }

        public string ProductCode { get; set; }
#nullable enable
        public string? CompanyId { get; set; }
#nullable restore
        public string Title { get; set; }

        public string Image { get; set; }

        public string Details { get; set; }

        public string ReleaseTime { get; set; }
        // public DateTime ReleaseTimex{get=>DateTime.Parse(ReleaseTime);}

        public string ExpireTime { get; set; }

        public string Country { get; set; }

        public string CountryFlag { get; set; }

        public string UrlLink { get; set; }

        public string Address { get; set; }

        public string RequireQuantity { get; set; }

        public string Contacts { get; set; }

        public string Mailbox { get; set; }

        public string Wechat { get; set; }

        public string Phone { get; set; }
#nullable enable
        public List<String>? CategoryStubs { get; set; }
#nullable restore
        public string Destination { get; set; }
        public string RequireAmount { get; set; }
        public string TargetPrice { get; set; }
        public string PaymentTerms { get; set; }
        public string ShippingTerms { get; set; }
        public string SupplierArea { get; set; }
        public string Follow { get; set; }
    }
}